/**
 * All Rights Reserved , Copyright (C) 2021 , 青岛鼎信通讯股份有限公司
 * MpmProjectPlanService
 * 项目策划
 * 修改纪录
 * 2021-01-07 版本：1.0 wudaliang 创建。
 *
 * @version 版本：1.0
 * @author 作者：wudaliang
 * 创建日期：2021-01-07
 */
package com.topscomm.mpm.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.topscomm.basic.exception.MessageException;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.basic.util.SQLAdapter;
import com.topscomm.cbo.pojo.CboUserEntity;
import com.topscomm.cbo.service.impl.CboApprovalNodeInsService;
import com.topscomm.cbo.service.impl.CboUserService;
import com.topscomm.main.hessian.IBaseChangeLogService;
import com.topscomm.mis.controller.IMisDeptArchController;
import com.topscomm.mpm.MpmSystemConst;
import com.topscomm.mpm.pojo.*;
import com.topscomm.mpm.utils.MessageUtil;
import com.topscomm.pub.util.*;
import com.topscomm.tap.TapEntity;
import com.topscomm.tap.TapService;
import com.topscomm.tap.common.DatacodeCache;
import com.topscomm.tap.common.FlowDatacodeCache;
import com.topscomm.tap.common.SessionUserBean;

import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.topscomm.tap.common.TapSystemConst;
import lombok.SneakyThrows;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.topscomm.mpm.service.IMpmProjectPlanService;
import com.topscomm.mpm.service.impl.auto.MpmProjectPlanServiceAuto;
import com.topscomm.basic.BasicEntity;
import com.topscomm.basic.util.PrimaryKeyUtil;
import com.topscomm.cbo.pojo.CboApprovalNodeEntity;
import com.topscomm.cbo.pojo.CboApprovalNodeInsEntity;
import com.topscomm.cbo.pojo.CboDeptEntity;
import com.topscomm.cbo.service.ICboMessageAppService;
import com.topscomm.cbo.service.ICboMessageSysService;
import com.topscomm.cbo.service.impl.CboDeptService;

@Service(value = "mpmProjectPlanService")
@Scope(value = "singleton")
public class MpmProjectPlanService extends MpmProjectPlanServiceAuto implements IMpmProjectPlanService {
	FlowDatacodeCache flowDatacodeCache = new FlowDatacodeCache();
	DatacodeCache datacodeCache = new DatacodeCache();
	protected List<Map<String, Object>> flowidList = new ArrayList();
	private static final Logger logger = LoggerFactory.getLogger(MpmProjectPlanService.class);
	@Autowired
	private MpmProjectService mpmProjectService;
	@Autowired
	private MpmProjectMilepostService mpmProjectMilepostService;
	@Autowired
	private MpmProjectTaskService mpmProjectTaskService;
	@Autowired
	private ICboMessageAppService cboMessageAppService;
	@Autowired
	private ICboMessageSysService cboMessageSysService;
	@Autowired
	private MpmProjectPlanService mpmProjectPlanService;
	@Autowired
	private CboApprovalNodeInsService cboApprovalNodeInsService;
	@Autowired
	private CboUserService cboUserService;
	@Autowired
	private MpmProjectAppointmentService mpmProjectAppointmentService;
	@Autowired
	private MpmProjectSquaredService mpmProjectSquaredService;
	@Autowired
	private MpmProjectFishFirstService mpmProjectFishFirstService;
	@Autowired
	private IBaseChangeLogService baseChangeLogService;
	@Autowired
	private MpmProjectTaskHistoryService mpmProjectTaskHistoryService;
	/**
	 * @param entity
	 * @throws ServiceException
	 * @author: wudaliang
	 * @date: 2021-01-07
	 * @description:单号生成
	 * @modify:
	 */
	@Override
	protected void beforeInsert(BasicEntity entity) throws ServiceException {
		super.beforeInsert(entity);
		if (entity.getId() <= 0) {// 赋值Id和单号
			long[] arrayId = PrimaryKeyUtil.GeneIDs(entity.getTableName(), 1);
			entity.setId(arrayId[0]);
			StringBufferProxy sql = new StringBufferProxy();
			sql.appendSingle("enabled =1 and state=9 and projectcode = '{0}'", entity.getValue("projectcode"));
			List<MpmProjectPlanEntity> entites = this
					.queryByWhere(sql.toString());
			if (entites.size() < 1) {
				entity.setValue("version", "V1.0");
			} else {
				String versionStr = entites.get(0).getVersion();
				String subStr = versionStr.substring(1,versionStr.indexOf("."));
				int a = Integer.parseInt(subStr);
				a++;
				entity.setValue("version", "V" + a + ".0");
			}
			String docNo = String.valueOf(arrayId[0]);
			docNo = docNo.substring(0, 6) + docNo.substring(9);
			entity.setValue(MpmProjectPlanEntity.FieldDocno, docNo);
			MpmProjectPlanEntity mpmProjectPlanEntity = (MpmProjectPlanEntity) entity;
			//赋值策划编号
			String proposalcode = this.generateProposalcode(mpmProjectPlanEntity);
			entity.setValue(MpmProjectPlanEntity.FieldProposalcode, proposalcode);
		}
	}

	/***
	 * @description: 生成策划编号
	 * @param mpmProjectPlanEntity
	 * @return
	 * @author: jiangtao1
	 * @date: 2021/12/1 14:51
	 * @modify:
	 */
	private String generateProposalcode(MpmProjectPlanEntity mpmProjectPlanEntity) {
		StringBuffer proposalcode = new StringBuffer();
		// 前两位
		proposalcode.append("CH");
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("projectcode = '{0}'", mpmProjectPlanEntity.getProjectcode());
		MpmProjectEntity mpmProjectEntity = mpmProjectService.queryObjectByWhere(sql.toString());
		if (mpmProjectEntity == null) {
			throw new ServiceException("该策划没有对应的立项信息，请核对！");
		}
		String projectlevel = mpmProjectEntity.getProjectlevel();
		String[] array = { "A", "B", "C", "D" };
		projectlevel = array[ConvertUtil.convertToInt(projectlevel)];
		// 第三位
		proposalcode.append(projectlevel);
		SimpleDateFormat sdFormat = new SimpleDateFormat("yyMMdd");
		String datacode = sdFormat.format(new Date());
		// 第4-7位
		proposalcode.append(datacode.substring(0, 4));
		// 第8-10位
		if (StringUtil.isEmpty(mpmProjectPlanEntity.getProposalcode())) {
			sql.clear();
			sql.appendSingle(" length({0}) = 10", MpmProjectPlanEntity.FieldProposalcode);
			List<Map<String, Object>> proposalcodelist = mpmProjectPlanService.queryMapForPage(sql.toString(), 1, 10, "createon", "desc");
			if (proposalcodelist.size() == 0) {
				proposalcode.append("001");
			} else {
				String lastproposalcode = ConvertUtil.convertToString(proposalcodelist.get(0).get("proposalcode"));
				String lastmonth = lastproposalcode.substring(5, 7);
				if (datacode.substring(2, 4).equals(lastmonth)) {
					DecimalFormat decimalFormat = new DecimalFormat("000");
					String substring1 = lastproposalcode.substring(7);
					int i = Integer.parseInt(substring1) + 1;
					proposalcode.append(decimalFormat.format(i));
				} else {
					proposalcode.append("001");
				}
			}
		} else {
			proposalcode.append("001");
		}
		return proposalcode.toString();
	}

	/***
	 * @description: 新添加注释，主要为flowid赋值，是否添加里程碑及任务控制和里程碑及任务时间与策划时间校验
	 * @param entity
	 * @param sessionUserBean
	 * @return
	 * @author: jiangtao1
	 * @date: 2021/12/1 14:26
	 * @modify:
	 */
	@SneakyThrows
	@Transactional(rollbackFor = Exception.class)
	@Override
	protected void beforeSubmit(TapEntity entity, SessionUserBean sessionUserBean) {
		super.beforeSubmit(entity, sessionUserBean);
		MpmProjectPlanEntity mpmProjectPlanEntity = (MpmProjectPlanEntity) entity;
		// 策划提交审批时，检测任命是否已审核完毕，如果任命未审核完毕，不允许策划提交审批
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("projectcode = '{0}' and state = 9 and enabled = 1",mpmProjectPlanEntity.getProjectcode());
		List<MpmProjectAppointmentEntity> mpmProjectAppointmentEntityList = mpmProjectAppointmentService.queryByWhere(sql.toString());
		if(mpmProjectAppointmentEntityList.size() == 0) {
			throw new MessageException("任命未审批完成，请在任命审批完成后再提交审批！");
		}
		// 审批流程赋值
		this.flowidList = flowDatacodeCache
				.getApprovalFlowListMap("ApprovalFlow_MpmProjectPlan",
						mpmProjectPlanEntity.getApplyusercode(), "sortcode");
		if (flowidList.size() > 0) {
			mpmProjectPlanEntity.setFlowid(ConvertUtil.convertToLong(flowidList.get(0).get("id")));
		} else {
			throw new ServiceException("没有匹配的审批流，请联系管理员！");
		}
		long planid = mpmProjectPlanEntity.getId();
		sql.clear();
		sql.appendSingle("planid = '{0}' and enabled= 0 order by planfinishtime,id asc", planid);
		List<MpmProjectMilepostEntity> mpmProjectMilepostEntityList = mpmProjectMilepostService.queryByWhere(sql.toString());
		if (mpmProjectMilepostEntityList.size() == 0) {
			throw new MessageException("未添加里程碑及任务，添加里程碑及任务后再提交审批！");
		}
		String projectcode = mpmProjectPlanEntity.getProjectcode();
		sql.clear();
		//里程碑及任务所属项目的计划结束时间
		sql.appendSingle("projectcode = '{0}'", projectcode);
		MpmProjectEntity mpmProjectEntity = mpmProjectService.queryObjectByWhere(sql.toString());
		Date projectplanenddate = mpmProjectEntity.getPlanenddate();
		for (MpmProjectMilepostEntity t : mpmProjectMilepostEntityList) {
			if (t.getPlanfinishtime().compareTo(projectplanenddate) > 0) {
				throw new MessageException("里程碑及任务的计划达成时间不能大于所属项目的计划结束时间！");
			}
		}
		// 策划变更存储basechangelog表变更信息
		sql.clear();
		sql.appendSingle(" enabled = 1 and projectcode = '{0}' and state = 9 order by createon desc ", projectcode);
		List<MpmProjectPlanEntity> oldPlanEntities = this.queryByWhere(sql.toString());
		if (!CollectionUtil.isEmpty(oldPlanEntities)) {
			this.approvalSavePlanLog(mpmProjectPlanEntity, oldPlanEntities.get(0));
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	protected void deleteBefore(String whereSql) {
		super.deleteBefore(whereSql);
		//找到这条策划
		List<MpmProjectPlanEntity> mpmProjectPlanEntities = this.queryByWhere(whereSql);
		if (mpmProjectPlanEntities.size() == 0) {
			return;
		}
		String planid = ConvertUtil.convertToString(mpmProjectPlanEntities.get(0).getId());
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date plandate = mpmProjectPlanEntities.get(0).getCreateon();
		String createdate = sdf.format(plandate);
		String projectcode = mpmProjectPlanEntities.get(0).getProjectcode();
		// 删除对应的任务，由于任务可能挂到不同的策划上，因此只可以删除创建时间之后的任务
		StringBufferProxy delsql = new StringBufferProxy();
		delsql.appendSingle("projectcode = '{0}' and createon >= {1} ", projectcode, SQLAdapter.toDateLong(createdate));
		mpmProjectTaskService.deleteByWhere(delsql.toString());
		//删除里程碑及任务
		delsql.clear();
		delsql.appendSingle(" planid = '{0}'", planid);
		mpmProjectMilepostService.deleteByWhere(delsql.toString());
		// 删除该策划对应的任务历史记录
		delsql.clear();
		delsql.appendSingle(" planid = '{0}'", planid);
		mpmProjectTaskHistoryService.deleteByWhere(delsql.toString());
	}

	/***
	 * @description: 发送策划App通知消息
	 * @param mpmProjectPlanEntity
	 * @return
	 * @author: jiangtao1
	 * @date: 2021/12/1 14:46
	 * @modify:
	 */
	public void sendMessageAppAndSys(MpmProjectPlanEntity mpmProjectPlanEntity,String mpmId) {
		StringBufferProxy content = new StringBufferProxy();
		Map<String, Object> messageAppmap = new HashMap<String, Object>();
		content.appendSingle("您提交的【{0}】策划书已审批通过，策划书编号为{1}，请于2天内组织召开项目开工会",
				mpmProjectPlanEntity.getProjectname(), mpmProjectPlanEntity.getProposalcode());
		messageAppmap.put("usercode", mpmProjectPlanEntity.getUsercode());
		messageAppmap.put("content", content.toString());
		messageAppmap.put("extendfield1", "策划审批通知");
		messageAppmap.put("sendtype", "0");
		messageAppmap.put("sourcetype", MpmProjectPlanEntity.tableName);
		messageAppmap.put("sourceid", mpmId);
		cboMessageAppService.insertMap(messageAppmap);
		// 系统通知消息
		Map<String, Object> messageSysAppmap = new HashMap<String, Object>();
		messageSysAppmap.put("receivercode", mpmProjectPlanEntity.getUsercode());
		messageSysAppmap.put("receivername", mpmProjectPlanEntity.getUsername());
		messageSysAppmap.put("content", content.toString());
		messageSysAppmap.put("subject", "策划审批通知");
		messageSysAppmap.put("ishtm", "0");
		messageSysAppmap.put("sourcetype", MpmProjectPlanEntity.tableName);
		messageSysAppmap.put("sourceid", mpmId);
		cboMessageSysService.insertMap(messageSysAppmap);
	}

	/**
	 * @return Map<String, Object>
	 * @author houyuhang
	 * @Description 首页策划超期
	 * @Date 2021/11/29
	 **/
	@Override
	public Map<String, Object> queryOverduePlan(Map<String, Object> paraMap) {
		Map<String, Object> overduePlanResult = new HashMap<>();
		StringBufferProxy sql = new StringBufferProxy();
		// 项目状态为进行中的数据权限内项目，且任命签署时间早于今日之前的七个工作日
		sql.appendSingle(" MpmProject.projectstate= '{0}' and MpmProject.enabled = 1 and {1} ",MpmSystemConst.ExecuteStateCode,
				mpmProjectService.whereExistsSqlForIndex(MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode,
						ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
		// 策划超期拼接字符串,项目任命签署时间不为空，且为首次任命，但项目策划不存在或者只存在一条未审批完成的策划
		sql.appendSingle(" AND MPMPROJECTAPPOINTMENT.SIGNDATE IS NOT NULL AND NOT EXISTS " +
				" (SELECT ID FROM MPMPROJECTAPPOINTMENT MPMAPP WHERE MPMAPP.PROJECTCODE = MPMPROJECTAPPOINTMENT.PROJECTCODE " +
				" AND MPMAPP.SIGNDATE < MPMPROJECTAPPOINTMENT.SIGNDATE) AND (MPMPROJECTPLAN.ID IS NULL" +
				" OR (MPMPROJECTPLAN.STATE < 9 AND NOT EXISTS( SELECT ID FROM MPMPROJECTPLAN PLAN WHERE" +
				" PLAN.PROJECTCODE = MPMPROJECTPLAN.PROJECTCODE AND PLAN.ID != MPMPROJECTPLAN.ID)))");
		// 获取7天之前的日期
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		String overduePlanTime = MpmSystemConst.overduePlanTime;
		int time = Integer.parseInt(overduePlanTime) * (-1);
		calendar.add(Calendar.DATE,time);
		Date overdueDate = calendar.getTime();
		String overdueTime = DateUtil.dateToString(overdueDate,"yyyy-MM-dd");
		Map<String,Object> dataMap = new HashMap<>();
		dataMap.put("whereSql",sql.toString());
		dataMap.put("overdue",1);
		dataMap.put("overduetime",overdueTime);
		int countPlan = mpmProjectService.getCount(dataMap, "queryPlanOverdue");
		overduePlanResult.put("code", "overduePlanNum");
		overduePlanResult.put("name", "超期策划");
		overduePlanResult.put("iconImg", "/static/images/paojectManager/overduePlan.png");
		overduePlanResult.put("value", countPlan);
		return overduePlanResult;
	}

	/**
	 * @return Map<String, Object>
	 * @author houyuhang
	 * @Description 首页信息概览策划待办
	 * @Date 2021/11/29
	 **/
	@Override
	public Map<String, Object> queryBacklogPlan(Map<String, Object> paraMap) {
		Map<String, Object> backlogPlanResult = new HashMap<>();
		StringBufferProxy sql = new StringBufferProxy();
		// 项目状态为进行中的数据权限内项目
		sql.appendSingle(" MpmProject.projectstate = '{0}' and MpmProject.enabled = 1 and {1} ",MpmSystemConst.ExecuteStateCode,
				mpmProjectService.whereExistsSqlForIndex(MpmProjectEntity.tableName, MpmProjectEntity.FieldProjectcode,
						ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
		// 策划待办拼接字符串,项目任命签署时间不为空，且为首次任命，但项目策划不存在或者只存在一条未提交审批的策划
		sql.appendSingle(" AND MPMPROJECTAPPOINTMENT.SIGNDATE IS NOT NULL AND NOT EXISTS " +
				" (SELECT ID FROM MPMPROJECTAPPOINTMENT MPMAPP WHERE MPMAPP.PROJECTCODE = MPMPROJECTAPPOINTMENT.PROJECTCODE " +
				" AND MPMAPP.SIGNDATE < MPMPROJECTAPPOINTMENT.SIGNDATE) AND (MPMPROJECTPLAN.ID IS NULL" +
				" OR (MPMPROJECTPLAN.STATE = 0 AND NOT EXISTS( SELECT ID FROM MPMPROJECTPLAN PLAN WHERE" +
				" PLAN.PROJECTCODE = MPMPROJECTPLAN.PROJECTCODE AND PLAN.ID != MPMPROJECTPLAN.ID)))");
		Map<String, Object> dataMap = new HashMap<>();
		dataMap.put("whereSql", sql.toString());
		int countBacklogPlan = mpmProjectService.getCount(dataMap, "queryPlanOverdue");
		backlogPlanResult.put("code", "backlogPlanNum");
		backlogPlanResult.put("name", "策划待办");
		backlogPlanResult.put("iconImg", "/static/images/paojectManager/backlogPlan.png");
		backlogPlanResult.put("value", countBacklogPlan);
		return backlogPlanResult;
	}
	/**
	 * @return void
	 * @author houyuhang
	 * @Description 将旧策划书有效性置为0，并把旧策划书下的里程碑及任务有效性全部置为0,
	 * 将新策划书有效性置为1，并把新策划书下里程碑及任务有效性全部置为1，同步新里程碑及任务和旧里程碑及任务的状态
	 * @Date 2021/12/02
	 **/
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void disableOldPlanAndMilePost(MpmProjectPlanEntity mpmOldPlan,List<MpmProjectMilepostEntity> mpmOldMilepostList,
										  MpmProjectPlanEntity mpmNewPlan,List<MpmProjectMilepostEntity> mpmNewMilepostList) {
		// 将旧策划书有效性置为0,将新策划书有效性置为1
		mpmOldPlan.setEnabled(0);
		mpmNewPlan.setEnabled(1);
		List<BasicEntity> mpmProjectPlanEntities = new ArrayList<BasicEntity>();
		mpmProjectPlanEntities.add(mpmOldPlan);
		mpmProjectPlanEntities.add(mpmNewPlan);
		this.updateBatch(mpmProjectPlanEntities);
		// 旧策划书下的里程碑及任务有效性全部置为0
		Map<String,List<MpmProjectMilepostEntity>> mpmOldMilePost = mpmOldMilepostList.stream().collect
				(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.getOperatecode())));
		for(MpmProjectMilepostEntity mpmProjectOldMilepostEntity: mpmOldMilepostList) {
			mpmProjectOldMilepostEntity.setEnabled(0);
		}
		// 新策划书下里程碑及任务有效性全部置为1,同步新里程碑及任务和旧里程碑及任务的状态
		for(MpmProjectMilepostEntity mpmProjectNewMilepostEntity: mpmNewMilepostList) {
			mpmProjectNewMilepostEntity.setEnabled(1);
			String newOperatecode = ConvertUtil.convertToString(mpmProjectNewMilepostEntity.getOperatecode());
			// 如果新里程碑及任务存在相同的旧里程碑及任务，将旧里程碑及任务的状态置给新里程碑及任务
			if(mpmOldMilePost.get(newOperatecode) != null && mpmOldMilePost.get(newOperatecode).size() > 0) {
				int milepostState = mpmOldMilePost.get(newOperatecode).get(0).getMilepoststate();
				Date actualFinishTime = mpmOldMilePost.get(newOperatecode).get(0).getActualfinishtime();
				mpmProjectNewMilepostEntity.setMilepoststate(milepostState);
				if (!ObjectUtil.isEmpty(actualFinishTime)) {
					mpmProjectNewMilepostEntity.setActualfinishtime(actualFinishTime);
				}
			}
		}
		List<BasicEntity> mpmProjectMilePostEntities = new ArrayList<BasicEntity>();
		mpmProjectMilePostEntities.addAll(mpmOldMilepostList);
		mpmProjectMilePostEntities.addAll(mpmNewMilepostList);
		mpmProjectMilepostService.updateBatch(mpmProjectMilePostEntities);
	}
	/**
	 * @return void
	 * @author houyuhang
	 * @Description 策划结束脚本-修改任务中里程碑及任务名称
	 * @Date 2021/12/02
	 **/
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateTaskMilepostName(MpmProjectPlanEntity mpmNewPlan,List<MpmProjectMilepostEntity> mpmNewMilepostList) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" projectcode = '{0}' ",mpmNewPlan.getProjectcode());
		List<MpmProjectTaskEntity> mpmProjectTaskEntityList = mpmProjectTaskService.queryByWhere(sql.toString());
		// 根据operatecode对新里程碑及任务进行分类，一个operatecode对应一个里程碑及任务
		Map<String,List<MpmProjectMilepostEntity>> mpmNewMilePostMap = mpmNewMilepostList.stream().collect
				(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.getOperatecode())));
		// 遍历任务，如果能找到该任务对应的里程碑及任务，就对任务的里程碑及任务名称进行更新
		for(MpmProjectTaskEntity mpmProjectTaskEntity : mpmProjectTaskEntityList) {
			String milepostCodeForTask = mpmProjectTaskEntity.getMilepostcode();
			if(mpmNewMilePostMap.get(milepostCodeForTask) != null && mpmNewMilePostMap.get(milepostCodeForTask).size() > 0) {
				String milepostname = mpmNewMilePostMap.get(milepostCodeForTask).get(0).getMilepostname();
				mpmProjectTaskEntity.setMilepostname(milepostname);
			}
		}
		// 使用updateBatch更新任务的历程碑名称
		List<BasicEntity> updateEntity = new ArrayList<>();
		updateEntity.addAll(mpmProjectTaskEntityList);
		mpmProjectTaskService.updateBatch(updateEntity);
	}
	/**
	 * @return void
	 * @author houyuhang
	 * @Description 如果新里程碑及任务改变了里程碑及任务责任人，需要将任务反馈和任务关闭的里程碑及任务责任人节点的办理人进行修改
	 * @Date 2021/12/03
	 **/
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateResponsibleCode(List<MpmProjectMilepostEntity> mpmOldMilepostList,List<MpmProjectMilepostEntity> mpmNewMilepostList) {
		// 旧里程碑及任务按照operatecode进行分类
		Map<String,List<MpmProjectMilepostEntity>> mpmOldMilepostMap = mpmOldMilepostList.stream().
				collect(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.getOperatecode())));
		// 将里程碑及任务责任人发生变化的新里程碑及任务存入changeList
		List<MpmProjectMilepostEntity> changeList = new ArrayList<>();
		for(MpmProjectMilepostEntity mpmProjectMilepostEntity : mpmNewMilepostList) {
			String operateCode = ConvertUtil.convertToString(mpmProjectMilepostEntity.getOperatecode());
			String responsibleCode = mpmProjectMilepostEntity.getResponsiblecode();
			if(mpmOldMilepostMap.get(operateCode) != null && !responsibleCode.equals(mpmOldMilepostMap.get(operateCode).get(0).getResponsiblecode())) {
				changeList.add(mpmProjectMilepostEntity);
			}
		}
		// 不存在里程碑及任务责任人发生变化的情况
		if(changeList.size() == 0) {
			return;
		}
		// 存在里程碑及任务责任人发生变化的情况
		List<BasicEntity> updateEntity = new ArrayList<>();
		StringBufferProxy sql = new StringBufferProxy();
		// 查询里程碑及任务下处于里程碑及任务责任人审批阶段的任务反馈和任务关闭流程
		String milepostId = changeList.stream().map(item -> ConvertUtil.convertToString(item.getId()))
				.collect(Collectors.joining("','","'","'"));
		// 任务反馈流程
		sql.appendSingle("MPMPROJECTMILEPOST.ID IN ({0}) and MPMPROJECTTASKFEEDBACK.STATE = 1 ",milepostId);
		List<Map<String,Object>> taskFeedbackApprovalList = mpmProjectMilepostService.queryMapByWhere(sql.toString(),"queryTaskFeedback");
		if(taskFeedbackApprovalList.size()>0) {
			for (Map<String, Object> taskFeedbackApprovalMap : taskFeedbackApprovalList) {
				// 查询人员code对应的id
				sql.clear();
				sql.appendSingle(" code = '{0}' ", ConvertUtil.convertToString(taskFeedbackApprovalMap.get("responsiblecode")));
				CboUserEntity cboUserEntity = cboUserService.queryObjectByWhere(sql.toString());
				// 查询里程碑及任务责任人正在审批的流程
				sql.clear();
				sql.appendSingle("SELECT CBOAPPROVALNODEINS.* FROM CBOAPPROVALNODEINS INNER JOIN CBOAPPROVALNODE " +
						"ON CBOAPPROVALNODEINS.NODEID = CBOAPPROVALNODE.ID WHERE CBOAPPROVALNODEINS.SOURCEID = '{0}' " +
						"AND  CBOAPPROVALNODEINS.SOURCETYPE = '{1}' AND STATE = 1 AND " +
						"CBOAPPROVALNODE.APPROVALPARAM LIKE '%milepostcheckfeedback%'",taskFeedbackApprovalMap.get("sourceid"),
						MpmProjectTaskFeedbackEntity.tableName);
				List<Map<String,Object>> feedbackList = cboApprovalNodeInsService.selectExecute(sql.toString());
				// 存在任务反馈流程正处于里程碑及任务责任人审批节点的流程，将里程碑及任务责任人进行更换
				if(feedbackList.size() > 0) {
					CboApprovalNodeInsEntity cboApprovalNodeInsEntity = new CboApprovalNodeInsEntity();
					cboApprovalNodeInsEntity.convertFromMap(feedbackList.get(0));
					cboApprovalNodeInsEntity.setApprovaluserid(cboUserEntity.getId());
					updateEntity.add(cboApprovalNodeInsEntity);
				}
			}
		}
		// 任务关闭流程
		sql.clear();
		sql.appendSingle("MPMPROJECTMILEPOST.ID IN ({0}) and MPMPROJECTTASKCLOSE.STATE = 1 ",milepostId);
		List<Map<String,Object>> taskCloseApprovalList = mpmProjectMilepostService.queryMapByWhere(sql.toString(),"queryTaskClose");
		if(taskCloseApprovalList.size() > 0) {
			for (Map<String, Object> taskCloseApprovalMap : taskCloseApprovalList) {
				// 查询人员code对应的id
				sql.clear();
				sql.appendSingle(" code = '{0}' ", ConvertUtil.convertToString(taskCloseApprovalMap.get("responsiblecode")));
				CboUserEntity cboUserEntity = cboUserService.queryObjectByWhere(sql.toString());
				// 查询里程碑及任务责任人正在审批的流程
				sql.clear();
				sql.appendSingle("SELECT CBOAPPROVALNODEINS.* FROM CBOAPPROVALNODEINS INNER JOIN CBOAPPROVALNODE " +
								"ON CBOAPPROVALNODEINS.NODEID = CBOAPPROVALNODE.ID WHERE CBOAPPROVALNODEINS.SOURCEID = '{0}' " +
								"AND  CBOAPPROVALNODEINS.SOURCETYPE = '{1}' AND STATE = 1 AND " +
								"CBOAPPROVALNODE.APPROVALPARAM LIKE '%milepostcheckclose%'",taskCloseApprovalMap.get("sourceid"),
						MpmProjectTaskCloseEntity.tableName);
				List<Map<String,Object>> closeList = cboApprovalNodeInsService.selectExecute(sql.toString());
				// 存在任务关闭流程正处于里程碑及任务责任人审批节点的流程，将里程碑及任务责任人进行更换
				if(closeList.size() > 0) {
					CboApprovalNodeInsEntity cboApprovalNodeInsEntity = new CboApprovalNodeInsEntity();
					cboApprovalNodeInsEntity.convertFromMap(closeList.get(0));
					cboApprovalNodeInsEntity.setApprovaluserid(cboUserEntity.getId());
					updateEntity.add(cboApprovalNodeInsEntity);
				}
			}
		}
		// 更新任务反馈和任务关闭的里程碑及任务责任人节点办理人
		cboApprovalNodeInsService.updateBatch(updateEntity);
	}

	/**
	 * @return void
	 * @author zhangjunyao
	 * @Description 策划归档获取项目相关信息
	 * @Date 2021/12/14
	 **/
	public void getProjectInfo(List<Map<String, Object>> tempList) {
		String projectCodes = tempList.stream().map(map -> ConvertUtil.convertToString(map.get("projectcode")))
				.collect(Collectors.joining("','", "'", "'"));
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("projectcode in ({0})", projectCodes);
		List<MpmProjectEntity> projectEntities = mpmProjectService.queryByWhere(sql.toString());
		if (CollectionUtils.isEmpty(projectEntities)) {
			return;
		}
		Map<String, MpmProjectEntity> resultMap = projectEntities.stream().collect(Collectors.toMap(
				MpmProjectEntity::getProjectcode, mpmProjectEntity -> mpmProjectEntity, (v1, v2) -> v1));
		for (Map<String, Object> mapRow : tempList) {
			String projectCode = ConvertUtil.convertToString(mapRow.get("projectcode"));
			if (resultMap.containsKey(projectCode)) {
				MpmProjectEntity mpmProjectEntity = resultMap.get(projectCode);
				mapRow.put("projectname", mpmProjectEntity.getProjectname());
				mapRow.put("deptname", mpmProjectEntity.getDeptname());
				mapRow.put("target", mpmProjectEntity.getTarget());
				mapRow.put("projectmanager", mpmProjectEntity.getProjectmanager());
			}
		}
	}
	/**
	 * @return void
	 * @author houyuhang
	 * @Description 策划结束脚本更新任务的里程碑及任务名称字段
	 * @Date 2022/03/07
	 **/
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateMilepostNameForTask(MpmProjectMilepostEntity mpmProjectMilepostEntity) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" {0} = '{1}' ", MpmProjectTaskEntity.FieldMilepostcode, mpmProjectMilepostEntity.getOperatecode());
		List<MpmProjectTaskEntity> mpmProjectTaskEntities = mpmProjectTaskService.queryByWhere(sql.toString());
		if(mpmProjectTaskEntities.size() == 0) {
			return;
		}
		// 使用updateBatch更新任务的里程碑及任务名称
		List<BasicEntity> updateEntity = new ArrayList<>();
		for(MpmProjectTaskEntity mpmProjectTaskEntity : mpmProjectTaskEntities) {
			mpmProjectTaskEntity.setMilepostname(mpmProjectMilepostEntity.getMilepostname());
			updateEntity.add(mpmProjectTaskEntity);
		}
		mpmProjectTaskService.updateBatch(updateEntity);
	}
	/**
	 * @return boolean
	 * @author houyuhang
	 * @Description 短名单任务是否存在九宫格
	 * @Date 2022/11/11
	 **/
	public boolean haveSquaredData(String taskid) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" enabled = 1 and taskid = '{0}' ", taskid);
		List<MpmProjectSquaredEntity> mpmProjectSquaredEntities = mpmProjectSquaredService.queryByWhere(sql.toString());
		return mpmProjectSquaredEntities.size() > 0;
	}
	/**
	 * @return boolean
	 * @author houyuhang
	 * @Description 填写客户决策链分析的任务是否填写鱼骨图
	 * @Date 2022/11/16
	 **/
	public boolean haveFishData(List<String> fishTaskList, StringBufferProxy taskname) {
		// 没有填写客户决策链分析的任务，返回true
		if (CollectionUtil.isEmpty(fishTaskList)) {
			return true;
		}
		// 获取任务信息，用于拼接任务名称
		String fishTaskId = String.join(",", fishTaskList);
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" enabled = 1 and id in ({0}) ", fishTaskId);
		List<MpmProjectTaskEntity> mpmProjectTaskEntities = mpmProjectTaskService.queryByWhere(sql.toString());
		if (CollectionUtil.isEmpty(mpmProjectTaskEntities)) {
			return true;
		}
		sql.clear();
		sql.appendSingle(" enabled = 1 and taskid in ({0}) ", fishTaskId);
		List<MpmProjectFishFirstEntity> mpmProjectFishFirstEntities = mpmProjectFishFirstService.queryByWhere(sql.toString());
		// 没有鱼骨图信息，返回false
		if (CollectionUtil.isEmpty(mpmProjectFishFirstEntities)) {
			taskname.appendSingle(mpmProjectTaskEntities.stream().map(MpmProjectTaskEntity::getTaskname).collect(Collectors.joining("、")));
			return false;
		}
		// 有鱼骨图信息，遍历任务查看是否有鱼骨图
		Map<String, List<MpmProjectFishFirstEntity>> mpmProjectFishFirstMap = mpmProjectFishFirstEntities.stream().collect(Collectors.groupingBy(item -> ConvertUtil.convertToString(item.getTaskid())));
		boolean fishflag = true;
		for (MpmProjectTaskEntity tempEntity : mpmProjectTaskEntities) {
			String tempid = ConvertUtil.convertToString(tempEntity.getId());
			if (CollectionUtil.isEmpty(mpmProjectFishFirstMap.get(tempid))) {
				fishflag = false;
				taskname.appendSingle(tempEntity.getTaskname() + "、");
			}
		}
		if (!fishflag && taskname.length() > 1) {
			StringBufferProxy newTask = taskname.substring(0, taskname.length() - 1);
			taskname.clear();
			taskname.appendSingle(newTask.toString());
		}
		return fishflag;
	}
	/***
	 * @description: 任命变更审批时保存basechangelog表内容
	 * @return
	 * @author: houyuhang
	 * @date: 2023/02/06
	 * @modify:
	 */
	public void approvalSavePlanLog(MpmProjectPlanEntity newPlanEntity, MpmProjectPlanEntity oldPlanEntity) throws Exception {
		// 删除上次的basechangelog
		baseChangeLogService.deleteByWhere(" topsourcetype='"+newPlanEntity.getTableName()+"'"
				+ " and topsourceid='"+newPlanEntity.getId()+"'");
		// 保存basechangelog信息
		this.getBasePlanEntity(newPlanEntity.convertToMap(), oldPlanEntity.convertToMap());
	}
	/***
	 * @description: 获取变更具体内容
	 * @return
	 * @author: houyuhang
	 * @date: 2023/02/10
	 * @modify:
	 */
	public void getBasePlanEntity(Map<String, Object> newPlanMap, Map<String, Object> oldPlanMap) throws Exception {
		// 获取变更version记录
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" projectcode = '{0}' and state = 9 ", newPlanMap.get("projectcode"));
		List<MpmProjectPlanEntity> planList = this.queryByWhere(sql.toString());
		int version = planList.size() + 1;
		// 拼接比对字段
		Map<String, Object> changeMap = new HashMap<String, Object>();
		changeMap.put("topsourcetype",MpmProjectPlanEntity.tableName);
		changeMap.put("topsourceid", ConvertUtil.convertToString(newPlanMap.get("id")));
		changeMap.put("sourcetype", MpmProjectPlanEntity.tableName);
		changeMap.put("sourceid", ConvertUtil.convertToString(newPlanMap.get("id")));
		changeMap.put("newmap", newPlanMap);
		changeMap.put("oldmap", oldPlanMap);
		changeMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Edit);
		changeMap.put("version", version);
		Map<String, Object> changeResMap = this.getMainChangeLogEntity(changeMap);
		if (changeResMap != null) {
			baseChangeLogService.insertLogMap(changeResMap);
		}
		// 获取里程碑信息
		List<Map<String, Object>> oldMilepostList = mpmProjectMilepostService.queryMapByWhere(" planid=" + oldPlanMap.get("id"));
		List<Map<String, Object>> newMilepostList = mpmProjectMilepostService.queryMapByWhere(" planid=" + newPlanMap.get("id"));
		this.saveGeneralChangeEntity(newMilepostList, oldMilepostList, newPlanMap, version, MpmProjectMilepostEntity.tableName, MpmProjectPlanEntity.tableName);
		// 获取任务信息
		List<Map<String, Object>> oldTaskList = mpmProjectTaskHistoryService.queryMapByWhere(" planid=" + newPlanMap.get("id"));
		List<Map<String, Object>> newTaskList = mpmProjectTaskService.queryMapByWhere(" projectcode='" + newPlanMap.get("projectcode") + "'");
		if (!CollectionUtil.isEmpty(oldTaskList)) {
			this.saveGeneralTaskEntity(newTaskList, oldTaskList, newPlanMap, version, MpmProjectTaskEntity.tableName, MpmProjectPlanEntity.tableName);
		}
	}
	/***
	 * @description: 保存子表变更信息通用方法
	 * @return
	 * @author: houyuhang
	 * @date: 2023/02/10
	 * @modify:
	 */
	public void saveGeneralChangeEntity(List<Map<String, Object>> teamTypeList, List<Map<String, Object>> teamTypeHistoryList,
										Map<String, Object> inputMap, int version, String sourcetype, String topsourcetype) throws Exception {
		Map<String, Object> changeProductMap = new HashMap<String, Object>();
		changeProductMap.put("sourcetype", sourcetype);
		changeProductMap.put("topsourcetype", topsourcetype);
		changeProductMap.put("topsourceid", ConvertUtil.convertToString(inputMap.get("id")));
		changeProductMap.put("version", version);
		List<String> noDelIds = new ArrayList<String>();
		for (Map<String, Object> newItem : teamTypeList) {
			// 如果operatecode与id相等，则判断为新增的里程碑，否则为编辑的里程碑
			if (newItem.containsKey("operatecode") && !ConvertUtil.convertToString(newItem.get("id")).equals(newItem.get("operatecode").toString())) {
				boolean hasHistory = false;
				Map<String, Object> matchHistory = new HashMap<String, Object>();
				for (Map<String, Object> historyItem : teamTypeHistoryList) {
					if (newItem.get("operatecode").toString().equals(historyItem.get("operatecode").toString())) {
						hasHistory = true;
						matchHistory = historyItem;
					}
				}
				if (hasHistory) {
					noDelIds.add(ConvertUtil.convertToString(matchHistory.get("id")));
					changeProductMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Edit);
					changeProductMap.put("newmap", newItem);
					changeProductMap.put("oldmap", matchHistory);
					changeProductMap.put("sourceid", newItem.get("id"));
					Map<String, Object> perContent = this.getMainChangeLogEntity(changeProductMap);
					if(perContent != null){
						baseChangeLogService.insertLogMap(perContent);
					}
				}
			} else {
				changeProductMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Add);
				changeProductMap.put("newmap", newItem);
				changeProductMap.put("oldmap", newItem);
				changeProductMap.put("sourceid", newItem.get("id"));
				baseChangeLogService.insertLogMap(this.getMainChangeLogEntity(changeProductMap));
			}
		}
		// 删除
		if(noDelIds.size()>0) {
			String lowerFirst = Character.toLowerCase(sourcetype.charAt(0)) + sourcetype.substring(1);
			String serviceName = lowerFirst + "Service";
			TapService serviceBean = (TapService) SpringUtil.getBean(serviceName);
			List<Map<String,Object>> delProducts = serviceBean.queryMapByWhere( " planid =" + teamTypeHistoryList.get(0).get("planid") + " and id not in (" + StringUtils.join(noDelIds, ",") + ")");
			for(Map<String,Object> delItem : delProducts){
				changeProductMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Del);
				changeProductMap.put("newmap", delItem);
				changeProductMap.put("oldmap", delItem);
				changeProductMap.put("sourceid", delItem.get("id"));
				baseChangeLogService.insertLogMap(this.getMainChangeLogEntity(changeProductMap));
			}
		}
	}
	/***
	 * @description: 保存任务子表变更信息通用方法
	 * @return
	 * @author: houyuhang
	 * @date: 2023/02/10
	 * @modify:
	 */
	public void saveGeneralTaskEntity(List<Map<String, Object>> teamTypeList, List<Map<String, Object>> teamTypeHistoryList,
										Map<String, Object> inputMap, int version, String sourcetype, String topsourcetype) throws Exception {
		Map<String, Object> changeProductMap = new HashMap<String, Object>();
		changeProductMap.put("sourcetype", sourcetype);
		changeProductMap.put("topsourcetype", topsourcetype);
		changeProductMap.put("topsourceid", ConvertUtil.convertToString(inputMap.get("id")));
		changeProductMap.put("version", version);
		List<String> noDelIds = new ArrayList<String>();
		for (Map<String, Object> newItem : teamTypeList) {
		// 如果存在历史记录，则为edit，否则为add
			boolean hasHistory = false;
			Map<String, Object> matchHistory = new HashMap<String, Object>();
			for (Map<String, Object> historyItem : teamTypeHistoryList) {
				if (ConvertUtil.convertToString(newItem.get("id")).equals(ConvertUtil.convertToString(historyItem.get("tasksourceid")))) {
					hasHistory = true;
					matchHistory = historyItem;
					break;
				}
			}
			if (hasHistory) {
				noDelIds.add(ConvertUtil.convertToString(matchHistory.get("id")));
				changeProductMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Edit);
				changeProductMap.put("newmap", newItem);
				changeProductMap.put("oldmap", matchHistory);
				changeProductMap.put("sourceid", newItem.get("id"));
				Map<String, Object> perContent = this.getMainChangeLogEntity(changeProductMap);
				if(perContent != null){
					baseChangeLogService.insertLogMap(perContent);
				}
			} else {
				changeProductMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Add);
				changeProductMap.put("newmap", newItem);
				changeProductMap.put("oldmap", newItem);
				changeProductMap.put("sourceid", newItem.get("id"));
				baseChangeLogService.insertLogMap(this.getMainChangeLogEntity(changeProductMap));
			}
		}
		// 删除
		if(noDelIds.size()>0 && teamTypeHistoryList.size() > 0) {
			List<Map<String,Object>> delProducts = mpmProjectTaskHistoryService.queryMapByWhere( " planid =" + teamTypeHistoryList.get(0).get("planid") + " and id not in (" + StringUtils.join(noDelIds, ",") + ")");
			for(Map<String,Object> delItem : delProducts){
				changeProductMap.put("baselogoperatetype", MpmSystemConst.BaseLogOperateTypeEnum.Del);
				changeProductMap.put("newmap", delItem);
				changeProductMap.put("oldmap", delItem);
				changeProductMap.put("sourceid", delItem.get("id"));
				baseChangeLogService.insertLogMap(this.getMainChangeLogEntity(changeProductMap));
			}
		}
	}
	/***
	 * @description: 提醒项目PMO和省区PMO策划变更的内容
	 * @return
	 * @author: houyuhang
	 * @date: 2023/02/10
	 * @modify:
	 */
	public void sendMessagePlanToPMO(MpmProjectPlanEntity mpmProjectPlanEntity, MpmProjectEntity mpmProjectEntity) throws Exception {
		// 获取消息发送人（项目PMO和省区PMO）
		List<Map<String, Object>> receiverList = this.getMessageReceiverPMO(mpmProjectEntity.getDeptcommoncode());
		if (CollectionUtil.isEmpty(receiverList)) {
			return;
		}
		Map<String, Object> paraMap = new HashMap<>();
		paraMap.put("topSourceType", MpmProjectPlanEntity.tableName);
		paraMap.put("topSourceId", mpmProjectPlanEntity.getId());
		List<Map<String, Object>> baseChangeLog = baseChangeLogService.queryChangeLogByOptions(paraMap);
		baseChangeLog = baseChangeLog.stream().filter(item -> MpmProjectMilepostEntity.tableName.equals(ConvertUtil.convertToString(item.get("sourcetype"))) ||
				MpmProjectTaskEntity.tableName.equals(ConvertUtil.convertToString(item.get("sourcetype")))).collect(Collectors.toList());
		// 如果里程碑和任务没有变化，不发送消息
		if (CollectionUtil.isEmpty(baseChangeLog)) {
			return;
		}
		// 拼接发送给PMO以及变更人的信息
		List<Map<String, Object>> appList = new ArrayList<>(), sysList = new ArrayList<>();
		List<Map<String, Object>> changeLogMilepost = baseChangeLog.stream().filter(item -> MpmProjectMilepostEntity.tableName.equals(ConvertUtil.convertToString(item.get("sourcetype")))).
				filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Add.equals(ConvertUtil.convertToString(item.get("operatetype"))) || MpmSystemConst.BaseLogOperateTypeEnum.Edit.equals(ConvertUtil.convertToString(item.get("operatetype")))).collect(Collectors.toList());
		List<Map<String, Object>> changeLogTask = baseChangeLog.stream().filter(item -> MpmProjectTaskEntity.tableName.equals(ConvertUtil.convertToString(item.get("sourcetype")))).
				filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Add.equals(ConvertUtil.convertToString(item.get("operatetype"))) || MpmSystemConst.BaseLogOperateTypeEnum.Edit.equals(ConvertUtil.convertToString(item.get("operatetype")))).collect(Collectors.toList());
		Map<String, Map<String, Object>> logMilepostForId = changeLogMilepost.stream().collect(Collectors.toMap(item -> ConvertUtil.convertToString(item.get("sourceid")), item -> item, (v1, v2) -> v1));
		Map<String, Map<String, Object>> logTaskForId = changeLogTask.stream().collect(Collectors.toMap(item -> ConvertUtil.convertToString(item.get("sourceid")), item -> item, (v1, v2) -> v1));
		// 获取里程碑和任务实例
		String milepostId = changeLogMilepost.stream().map(item -> ConvertUtil.convertToString(item.get("sourceid"))).collect(Collectors.joining("','","'", "'"));
		String taskId = changeLogTask.stream().map(item -> ConvertUtil.convertToString(item.get("sourceid"))).collect(Collectors.joining("','", "'", "'"));
		List<Map<String, Object>> milepostList = StringUtil.isEmpty(milepostId) ? new ArrayList<>() : mpmProjectMilepostService.queryMapByIds(milepostId);
		List<Map<String, Object>> taskList = StringUtil.isEmpty(taskId) ? new ArrayList<>() : mpmProjectTaskService.queryMapByIds(taskId);
		// 获取里程碑编号、任务编号
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" planid = '{0}' order by sortcode asc,planfinishtime asc,id asc ", mpmProjectPlanEntity.getId());
		List<Map<String, Object>> milepostEntitiesCode = mpmProjectMilepostService.queryMapByWhere(sql.toString());
		for (int i = 0 ; i < milepostEntitiesCode.size(); i++) {
			milepostEntitiesCode.get(i).put("generatemilepostcode", i+1);
		}
		sql.clear();
		sql.appendSingle(" projectcode = '{0}' ", mpmProjectPlanEntity.getProjectcode());
		List<Map<String, Object>> taskEntitiesCode = mpmProjectTaskService.queryMapByWhere(sql.toString());
		taskEntitiesCode = this.queryTaskCode(taskEntitiesCode);
		// 拼接operatetype(add/edit)
		this.concatOperateType(milepostList, logMilepostForId);
		this.concatOperateType(taskList, logTaskForId);
		// 拼接里程碑编号，任务编号
		milepostList = this.concatCode(milepostList, milepostEntitiesCode, MpmProjectMilepostEntity.tableName);
		taskList = this.concatCode(taskList, taskEntitiesCode, MpmProjectTaskEntity.tableName);
		if (CollectionUtil.isEmpty(milepostList) && CollectionUtil.isEmpty(taskList)) {
			return;
		}
		this.getPlanInfoDetail(baseChangeLog, appList, sysList, mpmProjectEntity, receiverList, milepostList, taskList);
		this.sendPlanToResponse(baseChangeLog, appList, sysList, mpmProjectEntity, milepostList, taskList);
		// 消息批量插入
		cboMessageAppService.insertList(appList);
		cboMessageSysService.insertList(sysList);
	}
	/***
	 * @description: 拼接发送给PMO以及变更人的策划变更信息
	 * @return
	 * @author: houyuhang
	 * @date: 2023/02/10
	 * @modify:
	 */
	public void getPlanInfoDetail(List<Map<String, Object>> baseChangeLog, List<Map<String, Object>> appList, List<Map<String, Object>> sysList, MpmProjectEntity mpmProjectEntity, List<Map<String, Object>> receiverList, List<Map<String, Object>> milepostList, List<Map<String, Object>> taskList) {
		String title = "销售项目策划变更通知";
		String projectLevel = datacodeCache.getValueDynamic("MpmProjectLevel", mpmProjectEntity.getProjectlevel(), "code", "name");
		StringBufferProxy content = new StringBufferProxy();
		// 变更消息拼接
		content.appendSingle("【{0}级项目：{1}】策划变更已完成，{2}请知悉。", projectLevel, mpmProjectEntity.getProjectname(), this.convertPlanMessageInfo(milepostList, taskList, "PMO"));
		for (Map<String, Object> receiver : receiverList) {
			appList.add(MessageUtil.createMessageAppMap(ConvertUtil.convertToString(receiver.get("usercode")), title, content.toString(), mpmProjectEntity.getId(),
					MpmProjectPlanEntity.tableName, 0));
			sysList.add(MessageUtil.createMessageSysMap(ConvertUtil.convertToString(receiver.get("usercode")), ConvertUtil.convertToString(receiver.get("username")), title, content.toString(),
					mpmProjectEntity.getId(), MpmProjectPlanEntity.tableName));
		}
	}
	/***
	 * @description: 拼接发送给变更人的策划变更信息
	 * @return
	 * @author: houyuhang
	 * @date: 2023/02/10
	 * @modify:
	 */
	public void sendPlanToResponse(List<Map<String, Object>> baseChangeLog, List<Map<String, Object>> appList, List<Map<String, Object>> sysList, MpmProjectEntity mpmProjectEntity, List<Map<String, Object>> milepostList, List<Map<String, Object>> taskList) {
		// 同一个用户多个里程碑、任务变更、只收到一条信息
		List<String> userList = new ArrayList<>();
		userList.addAll(milepostList.stream().map(item -> ConvertUtil.convertToString(item.get("responsiblecode"))).collect(Collectors.toList()));
		userList.addAll(taskList.stream().map(item -> ConvertUtil.convertToString(item.get("responsiblecode"))).collect(Collectors.toList()));
		Set<String> userSet = new HashSet<>(userList);
		Map<String, String> userRef = new HashMap<>();
		userRef.putAll(milepostList.stream().collect(Collectors.toMap(item -> ConvertUtil.convertToString(item.get("responsiblecode")), item -> ConvertUtil.convertToString(item.get("responsible")), (v1, v2) -> v1)));
		userRef.putAll(taskList.stream().collect(Collectors.toMap(item -> ConvertUtil.convertToString(item.get("responsiblecode")), item -> ConvertUtil.convertToString(item.get("responsible")), (v1, v2) -> v1)));
		// 遍历需要发送变更信息的用户
		String title = "销售项目策划变更通知";
		String projectLevel = datacodeCache.getValueDynamic("MpmProjectLevel", mpmProjectEntity.getProjectlevel(), "code", "name");
		for (String usercode : userSet) {
			StringBufferProxy content = new StringBufferProxy();
			// 属于该用户的里程碑任务变更
			content.appendSingle("【{0}级项目：{1}】策划变更已完成，{2}请知悉。", projectLevel, mpmProjectEntity.getProjectname(), this.convertPlanMessageInfo(milepostList.stream().filter(item -> usercode.equals(ConvertUtil.convertToString(item.get("responsiblecode")))).collect(Collectors.toList())
					, taskList.stream().filter(item -> usercode.equals(ConvertUtil.convertToString(item.get("responsiblecode")))).collect(Collectors.toList()), "USER"));
			appList.add(MessageUtil.createMessageAppMap(usercode, title, content.toString(), mpmProjectEntity.getId(),
					MpmProjectPlanEntity.tableName, 0));
			sysList.add(MessageUtil.createMessageSysMap(usercode, ConvertUtil.convertToString(userRef.get("usercode")), title, content.toString(),
					mpmProjectEntity.getId(), MpmProjectPlanEntity.tableName));
		}
	}
	/***
	 * @description: 拼接策划变更信息
	 * @return
	 * @author: houyuhang
	 * @date: 2023/02/11
	 * @modify:
	 */
	public String convertPlanMessageInfo(List<Map<String, Object>> milepostList, List<Map<String, Object>> taskList, String type) {
		String milepostnameAdd, milepostnameEdit, tasknameAdd, tasknameEdit;
		if (milepostList.size() + taskList.size() > 10 && "PMO".equals(type)) {
			milepostnameAdd = milepostList.stream().filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Add.equals(ConvertUtil.convertToString(item.get("logoperatetype")))).map(item -> ConvertUtil.convertToString(item.get("generatemilepostcode"))).collect(Collectors.joining("、"));
			milepostnameEdit = milepostList.stream().filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Edit.equals(ConvertUtil.convertToString(item.get("logoperatetype")))).map(item -> ConvertUtil.convertToString(item.get("generatemilepostcode"))).collect(Collectors.joining("、"));
			tasknameAdd = taskList.stream().filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Add.equals(ConvertUtil.convertToString(item.get("logoperatetype")))).map(item -> ConvertUtil.convertToString(item.get("generatetaskcode"))).collect(Collectors.joining("、"));
			tasknameEdit = taskList.stream().filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Edit.equals(ConvertUtil.convertToString(item.get("logoperatetype")))).map(item -> ConvertUtil.convertToString(item.get("generatetaskcode"))).collect(Collectors.joining("、"));
		} else {
			milepostnameAdd = milepostList.stream().filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Add.equals(ConvertUtil.convertToString(item.get("logoperatetype")))).map(item -> ConvertUtil.convertToString(item.get("milepostname"))).collect(Collectors.joining("、"));
			milepostnameEdit = milepostList.stream().filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Edit.equals(ConvertUtil.convertToString(item.get("logoperatetype")))).map(item -> ConvertUtil.convertToString(item.get("milepostname"))).collect(Collectors.joining("、"));
			tasknameAdd = taskList.stream().filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Add.equals(ConvertUtil.convertToString(item.get("logoperatetype")))).map(item -> ConvertUtil.convertToString(item.get("taskname"))).collect(Collectors.joining("、"));
			tasknameEdit = taskList.stream().filter(item -> MpmSystemConst.BaseLogOperateTypeEnum.Edit.equals(ConvertUtil.convertToString(item.get("logoperatetype")))).map(item -> ConvertUtil.convertToString(item.get("taskname"))).collect(Collectors.joining("、"));
		}
		StringBuilder changeInfo = new StringBuilder();
		if (!StringUtil.isEmpty(milepostnameAdd)) {
			changeInfo.append("新增里程碑：").append(milepostnameAdd).append("；");
		}
		if (!StringUtil.isEmpty(milepostnameEdit)) {
			changeInfo.append("发生变更里程碑：").append(milepostnameEdit).append("；");
		}
		if (!StringUtil.isEmpty(tasknameAdd)) {
			changeInfo.append("新增任务：").append(tasknameAdd).append("；");
		}
		if (!StringUtil.isEmpty(tasknameEdit)) {
			changeInfo.append("发生变更任务：").append(tasknameEdit).append("；");
		}
		return changeInfo.toString();
	}
	/**
	 * @author: houyuhang
	 * @date: 2023-02-13
	 * @description: 查询项目是否存在未审批完成的策划书
	 * @modify:
	 */
	public boolean checkPlanUnfinish(String projectcode) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" projectcode = '{0}' and state < 9 ", projectcode);
		return this.queryByWhere(sql.toString()).size() > 0;
	}
	/**
	 * @author: houyuhang
	 * @date: 2023-02-13
	 * @description: 为里程碑、任务拼接operatetype字段
	 * @modify:
	 */
	public void concatOperateType(List<Map<String, Object>> objectList, Map<String, Map<String, Object>> logMapForId) {
		for (Map<String, Object> objectMap : objectList) {
			Map<String, Object> tempLogMap = logMapForId.get(ConvertUtil.convertToString(objectMap.get("id")));
			if (ObjectUtil.isEmpty(tempLogMap)) {
				continue;
			}
			objectMap.put("logoperatetype", tempLogMap.get("operatetype"));
		}
	}
	/**
	 * @author: houyuhang
	 * @date: 2023-02-14
	 * @description: 获取里程碑、任务编号
	 * @modify:
	 */
	public List<Map<String, Object>> queryTaskCode(List<Map<String, Object>> taskEntitiesCode) {
		if (CollectionUtil.isEmpty(taskEntitiesCode)) {
			return new ArrayList<>();
		}
		return mpmProjectTaskService.generateTaskcode(taskEntitiesCode, new HashMap<>());
	}
	/**
	 * @author: houyuhang
	 * @date: 2023-02-14
	 * @description: 拼接里程碑编号并完成排序
	 * @modify:
	 */
	public List<Map<String, Object>> concatCode(List<Map<String, Object>> milepostList, List<Map<String, Object>> milepostEntitiesCode, String sourcetype) {
		List<Map<String, Object>> resList = new ArrayList<>();
		Map<String, Map<String, Object>> milepostMap = milepostList.stream().collect(Collectors.toMap(item -> ConvertUtil.convertToString(item.get("id")), item -> item, (v1, v2) -> v1));
		// 按顺序排列发生变更的里程碑、任务
		for (Map<String, Object> milepostEntitiesMap : milepostEntitiesCode) {
			Map<String, Object> tempMap = milepostMap.get(ConvertUtil.convertToString(milepostEntitiesMap.get("id")));
			if (ObjectUtil.isEmpty(tempMap)) {
				continue;
			}
			if (MpmProjectMilepostEntity.tableName.equals(sourcetype)) {
				tempMap.put("generatemilepostcode", ConvertUtil.convertToString(milepostEntitiesMap.get("generatemilepostcode")));
			} else {
				tempMap.put("generatetaskcode", ConvertUtil.convertToString(milepostEntitiesMap.get("generatetaskcode")));
			}
			resList.add(tempMap);
		}
		return resList;
	}
	/**
	 * @author houyuhang
	 * @Description 判断项目是否为A级项目经理为省总的项目
	 * @Date 2023/02/25
	 * @return
	 **/
	public boolean judgeProvinceManager(String projectcode) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" projectcode = '{0}' ", projectcode);
		MpmProjectEntity mpmProjectEntity = mpmProjectService.queryObjectByWhere(sql.toString());
		return !ObjectUtil.isEmpty(mpmProjectEntity) && MpmSystemConst.ProjectLevel.A.equals(mpmProjectEntity.getProjectlevel()) && mpmProjectService.queryIsProvinceManager(mpmProjectEntity.getProjectmanagercode());
	}
	/**
	 * @author houyuhang
	 * @Description 根据planid判断是否为变更策划
	 * @Date 2023/02/25
	 * @return
	 **/
	public boolean getProjectPlanChange(String planid) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" id = '{0}' and version != 'V1.0' ", planid);
		return this.getCount(sql.toString()) > 0;
	}
}
